/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "Logger.h"
#include "GameObject.h"
#include "BlenderMeshLoader.h"
#include "BlenderSkeletonLoader.h"
#include "BlenderLoadImpl.h"
#include "BlenderDefine.h"
#include "GEngine.h"

namespace GNgine
{
	BlenderLoadImpl::BlenderLoadImpl(SceneObject* sceneObject, std::string path)
		: SceneResourceLoadImpl(sceneObject,path),_success(false),_bFile(0)
	{
		assert(_sceneObject);
	}

	Object* BlenderLoadImpl::load()
	{
		_success=parseBlend();
		if(!_success){
			return 0;
		}
		convertObjects();
		
		return 0;//a list of objects,how to do
	}

	bool BlenderLoadImpl::parseBlend()
	{
		_bFile=new bParse::bBlenderFile(_path.c_str());
		
		_bFile->parse(false);
		if(!_bFile->ok()){
			return false;
		}
		
		return true;
	}

	//modify ogrekit(http://gamekit.googlecode.com)
	void BlenderLoadImpl::convertObjects()
	{
		bParse::bMain* mainPtr = _bFile->getMain();

		// Iterate through the scene.
		bParse::bListBasePtr *scenes = mainPtr->getScene();
		int numScenes = scenes->size();
		GNgLog.out("File contains %i scene(s)\n", numScenes);

		bParse::bListBasePtr* objects = mainPtr->getObject();
		int numObj = objects->size();
		GNgLog.out("File contains %i object(s)\n", numObj);
		
		bParse::bListBasePtr* cameras = mainPtr->getCamera();
		int numCam = cameras->size();
		GNgLog.out("File contains %i camera(s)\n", numCam);

		Blender::FileGlobal* glob = (Blender::FileGlobal*)_bFile->getFileGlobal();

		Blender::Scene* scene = (Blender::Scene*) glob->curscene;

		if (!scene){
			GNgLog.out("Warning: no default scene, perhaps an old Blender version? Taking first scene.\n");
			if (numScenes>=1){
				scene = (Blender::Scene*) scenes->at(0);
			}
		}

		// Loop all objects in the scene.
		Blender::Base *base = scene ? (Blender::Base*)scene->base.first : 0;
		
		if (!base){
			GNgLog.out("Warning: no scene\n");
		}else{
			beginScene(scene);
		}

		while (base){
			if (base->object){
				Blender::Object *object = base->object;
				//only process objects in active scene layer
				if (object->lay & scene->lay){
					convertObject(object);
				}
			}
			base = (Blender::Base*)base->next;
		}

		createParentChildHierarchy();
		convertConstraints();

	}

	void BlenderLoadImpl::createParentChildHierarchy()
	{
	}

	void BlenderLoadImpl::convertConstraints()
	{
	}


	void BlenderLoadImpl::convertObject(Blender::Object *object)
	{
		if(object==NULL){
			return;
		}
		
		switch (object->type){
		// OB_EMPTY
		case 0:
			convertEmptyObject(object);
			break;
		//OB_MESH
		case 1:
			convertMeshObject(object);
			break;
		//OB_LAMP
		case 10:
			convertLampObject(object);
			break;
		//OB_CAMERA
		case 11:
			convertCameraObject(object);
			break;
		
		// OB_ARMATURE 
		case 25:
			convertArmatureObject(object);
			break;
		}
		
	}
	//scene object mustn't be null
	void BlenderLoadImpl::convertMeshObject(Blender::Object *object)
	{
		if(!object||!object->data||object->type!=OB_MESH){
			return ;
		}
		GNgLog.out("\tObject is a mesh\n");
		
		Ogre::String name=object->id.name+2;//skip "OB"(+2) or not 

		BlenderMeshLoader *loader = new BlenderMeshLoader(_bFile, object);
		_sceneObject->createMesh(name,loader);

		_sceneObject->createMeshGameObject(name);
		

	}

	void BlenderLoadImpl::convertLampObject(Blender::Object *object)
	{
	}

	void BlenderLoadImpl::convertCameraObject(Blender::Object *object)
	{
	}

	void BlenderLoadImpl::convertEmptyObject(Blender::Object *object)
	{
	}

	void BlenderLoadImpl::convertArmatureObject(Blender::Object *object)
	{
		if(!object||!object->data||object->type!=OB_ARMATURE){
			return ;
		}
		GNgLog.out("\tObject is a armature\n");

		Ogre::String name=object->id.name+2;
		if(_sceneObject->hasObject(name)){
			GNgLog.out("Duplicate object/conversion call on object %s\n", object->id.name + 2);
			return;
		}

		BlenderSkeletonLoader* loader=new BlenderSkeletonLoader(_bFile,object);
		_sceneObject->createSkeleton(name,loader);

	}


	//modify ogrekit(http://gamekit.googlecode.com)
	void BlenderLoadImpl::beginScene(Blender::Scene *scene)
	{
		_bScene=scene;
		_bAnimRate=_bScene->r.frs_sec;

		GNgEngine.setAnimSpeed(_bScene->r.frs_sec);

		if (_bScene->world){
			// some sort of skybox system with world->mtex?
			Blender::World *world= scene->world;
			_ambient=Ogre::ColourValue(world->ambr,world->ambg,world->ambb);
			_worldColor=Ogre::ColourValue(world->horr,world->horg,world->horb);
		}

	}

}
